/*******************************************************************************
 * FilePath    : /Software/Examples_Adv_MS1656/adv_app_TxRx_1S/Src/BSP/Key.c
 * Version     : 1.0
 * Brief       :
 * Author      : AndrewHu
 * Company     : Shanghai MacroGiga Electronics CO.,Ltd
 * Email       : Hubinbo@macrogiga.com
 * Date        : 2020-03-24 15:42:28
 * LastEditors : AndrewHu
 * LastEditTime: 2023-12-28 17:32:17
 * Description :
 ******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <Includes.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define KEY_DELAY_SHORT 5  // unit-10ms
#define KEY_DELAY_TIMES 30 // unit-10ms
#define KEY_DELAY_LONG 200 // unit-10ms

#define KEY_FLAG_HL 0x01    // 按键状态
#define KEY_FLAG_SHORT 0x02 // 短按
#define KEY_FLAG_LONG 0x04  // 长按
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u8 keyFlag = 0x00;
u8 keyDelayShort = 0x00; // 按键去抖
u8 keyDelayTimes = 0x00; // 连按判断
u8 keyDelayLong = 0x00;  // 长按判断

u8 keyTimes = 0x00; // 连按次数
/* Private function ----------------------------------------------------------*/
static void KEY_Down_Event(void);
static void KEY_Up_Event(void);
static void KEY_Times_Event(void);
static void KEY_Long_Event(void);
/* extern --------------------------------------------------------------------*/
/*******************************************************************************
 * Function    : KEY_GPIO_Init
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-03-24 17:09:29
 * Description :
 ******************************************************************************/
static void KEY_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOC_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStruct.SlewRate = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct.Alternate = 0;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    // 按键配置中断
    /* Configure Button pin as input with External interrupt */
    GPIO_InitStruct.Mode = EXTI_MODE;
    GPIO_InitStruct.Exti.Enable = GPIO_EXTI_INT_ENABLE;
    GPIO_InitStruct.Exti.EdgeLevelSel = GPIO_EXTI_INT_EDGE;
    GPIO_InitStruct.Exti.RiseFallSel = GPIO_EXTI_INT_HIGHRISE;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    __HAL_GPIO_EXTI_CLEAR_FLAG(GPIOC, GPIO_PIN_3);
    /* Enable and set Button EXTI Interrupt to the lowest priority */
    HAL_NVIC_SetPriority(GPIOC_IRQn, PRIORITY_LOW);
    HAL_NVIC_EnableIRQ(GPIOC_IRQn);
}
static u8 IsKeyStatus(void)
{
    return HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_3);
}
/*******************************************************************************
 * Function    : KEY_Init
 * Brief       : 按键初始化
 * Parameter   :
 * Returns     :
 * Date        : 2020-03-24 16:28:55
 * Description :
 ******************************************************************************/
void KEY_Init(void)
{
    KEY_GPIO_Init();
}
/*******************************************************************************
 * Function    : KEY_Down_Callback
 * Brief       : 按键按下回调函数
 * Parameter   :
 * Returns     :
 * Date        : 2023-08-20 14:53:26
 * Description :
 ******************************************************************************/
__weak void KEY_Down_Callback(void)
{
}
/*******************************************************************************
 * Function    : KEY_Down_Event
 * Brief       : 按键按下动作
 * Parameter   :
 * Returns     :
 * Date        : 2023-08-20 14:53:26
 * Description :
 ******************************************************************************/
static void KEY_Down_Event(void)
{
    keyFlag |= KEY_FLAG_SHORT;
    keyTimes++; // 按键按下次数累计

    KEY_Down_Callback();
    // Uart_Send_String((u8 *)"\r\nKey Down", 10);
}
/*******************************************************************************
 * Function    : KEY_Up_Callback
 * Brief       : 按键松开回调函数
 * Parameter   :
 * Returns     :
 * Date        : 2023-08-20 14:53:26
 * Description :
 ******************************************************************************/
__weak void KEY_Up_Callback(void)
{
}
/*******************************************************************************
 * Function    : KEY_Up_Event
 * Brief       : 按键松开动作
 * Parameter   :
 * Returns     :
 * Date        : 2023-08-20 14:53:26
 * Description :
 ******************************************************************************/
static void KEY_Up_Event(void)
{
    keyFlag &= (~KEY_FLAG_SHORT);

    if (keyFlag & KEY_FLAG_LONG)
    { // 长按后松开
        keyFlag &= (~KEY_FLAG_LONG);
    }
    else
    { // 没有长按松开
    }
    KEY_Up_Callback();
    // Uart_Send_String((u8 *)"\r\nKey Up", 8);
}
/*******************************************************************************
 * Function    : KEY_Times_Callback
 * Brief       : 按键连按回调函数
 * Parameter   :
 * Returns     :
 * Date        : 2023-08-20 14:53:26
 * Description :
 ******************************************************************************/
__weak void KEY_Times_Callback(void)
{
}
/*******************************************************************************
 * Function    : KEY_Times_Event
 * Brief       : 按键连按处理
 * Parameter   :
 * Returns     :
 * Date        : 2023-08-20 14:53:26
 * Description :
 ******************************************************************************/
static void KEY_Times_Event(void)
{
    if (keyFlag & KEY_FLAG_SHORT)
    { // 当前按键为按下状态
    }
    else
    { // 当前按键为松开状态
    }

    if (keyTimes > 0x01)
    {
        KEY_Times_Callback();
        // Uart_Send_String((u8 *)"\r\nKey Times:0x", 14);
        // Uart_Send_Byte2Ascii(keyTimes);
    }

    keyTimes = 0x00;
}
/*******************************************************************************
 * Function    : KEY_Long_Callback
 * Brief       : 按键长按回调函数
 * Parameter   :
 * Returns     :
 * Date        : 2023-08-20 14:53:26
 * Description :
 ******************************************************************************/
__weak void KEY_Long_Callback(void)
{
}
/*******************************************************************************
 * Function    : KEY_Long_Event
 * Brief       : 按键长按处理
 * Parameter   :
 * Returns     :
 * Date        : 2023-08-20 14:53:26
 * Description :
 ******************************************************************************/
static void KEY_Long_Event(void)
{
    keyFlag |= KEY_FLAG_LONG;

    KEY_Long_Callback();
    // Uart_Send_String((u8 *)"\r\nKey Long", 10);
}
/*******************************************************************************
 * Function    : KEY_Scan
 * Brief       : 按键扫描
 * Parameter   :
 * Returns     :
 * Date        : 2020-03-25 16:57:53
 * Description :
 ******************************************************************************/
void KEY_Scan(void)
{
    if (IsKeyStatus())
    { // high
        if (keyFlag & KEY_FLAG_HL)
            keyDelayShort = 0x00;
    }
    else
    { // low
        if ((keyFlag & KEY_FLAG_HL) == 0x00)
            keyDelayShort = 0x00;
    }

    keyDelayShort++;
    if (keyDelayShort >= KEY_DELAY_SHORT)
    { // 按键状态改变
        keyDelayShort = 0x00;
        keyDelayTimes = 0x00;
        keyDelayLong = 0x00;

        if (keyFlag & KEY_FLAG_HL)
        { // high->low
            keyFlag &= (~KEY_FLAG_HL);
            KEY_Down_Event();
        }
        else
        { // low->high
            keyFlag |= KEY_FLAG_HL;
            KEY_Up_Event();
        }
    }

    // 连按判断
    if (keyDelayTimes <= KEY_DELAY_TIMES)
        keyDelayTimes++;

    if (keyDelayTimes == KEY_DELAY_TIMES)
    { // 连按超时
        KEY_Times_Event();
    }

    // 长按判断
    if (keyFlag & KEY_FLAG_SHORT)
    { // 按键按下
        if (keyDelayLong <= KEY_DELAY_LONG)
            keyDelayLong++;

        if (keyDelayLong == KEY_DELAY_LONG)
        { // 长按
            KEY_Long_Event();
        }
    }
}
